package com.jack.payment.rabbitmq.consumer;


import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.jack.payment.constant.enums.PaymentStatusEnum;
import com.jack.payment.dao.payment.PaymentAttachDao;
import com.jack.payment.entity.common.BusinessException;
import com.jack.payment.entity.generate.payment.PaymentAttachModel;
import com.jack.payment.entity.generate.payment.PaymentCallbackModel;
import com.jack.payment.rabbitmq.constant.RabbitmqConstant;
import com.jack.payment.rabbitmq.entity.QueueContentModel;
import com.jack.payment.rabbitmq.produer.MQSender;
import com.jack.payment.service.mongo.RequestLogServiceImpl;
import com.jack.payment.util.common.StringUtil;
import com.jack.payment.util.common.TimeUtil;
import com.rabbitmq.client.Channel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;

@Component
public class PaymentReceiver {
    private Logger log = LoggerFactory.getLogger(PaymentReceiver.class);
    /** 请求成功必须返回的 **/
    private final static String SUCCESS = "success";
    /**
     * 死信队列延迟时间
     */
    private final static Long BASIC_DELAY_TIME = 20000L;

    @Autowired
    private PaymentAttachDao paymentAttachDao;
    @Autowired
    private MQSender mqSender;
    @Autowired
    private RequestLogServiceImpl requestLogService;

    /**
     * 支付成功 后消息队列处理相关
     * @param message
     * @param queueContentModel
     * @param channel
     * @throws IOException
     */
    @RabbitListener(queues = RabbitmqConstant.QUEUE_PAYMENT_COMMON)
    public void paymentSuccessQueueHandler(Message message, QueueContentModel<String> queueContentModel, Channel channel) throws IOException {
        channel.basicQos(10);
        log.info("正常支付 正在进行支付模块数据消费!!!! 队列id==>>>{}, 消息主题为==>>>{}, 已消费了==>>>{}次",
                queueContentModel.getId(),
                queueContentModel.getSubject(),
                queueContentModel.getCount());
        Long currentTime = TimeUtil.getCurrentTime();
        String orderNo = queueContentModel.getData();
        PaymentAttachModel paymentAttachModel = paymentAttachDao.getAppointPayAttach(orderNo);
        if (paymentAttachModel != null) {
            // 构建 本次支付call 数据记录, 用于记录支付每次调用后的执行状态
            PaymentCallbackModel paymentCallbackModel = new PaymentCallbackModel().builder()
                    .id(queueContentModel.getId())
                    .webhook(paymentAttachModel.getWebhook())
                    .type(1)
                    .isManual(0)
                    .requestTime(currentTime)
                    .build();
            QueueContentModel<PaymentCallbackModel> thisQueueContent =
                    new QueueContentModel<PaymentCallbackModel>(queueContentModel);
            try {
                if (queueContentModel.getStatus() == 0) {
                    String resultBody = executeUserWebhook(paymentAttachModel.getWebhook(), "");
                    // 捕获回调结果是否成功
                    paymentCallbackModel.setCallContent(resultBody); // 执行结果
                    if (!resultBody.equals(SUCCESS)) {
                        throw new BusinessException();
                    }
                    paymentAttachModel.setStatus(PaymentStatusEnum.PAY_SUCCESS.getStat());
                    paymentCallbackModel.setStatus(1);  // 表示 本次执行成功
                    thisQueueContent.setStatus(1);
                }
                thisQueueContent.setCount(thisQueueContent.getCount() + 1);
            } catch (Exception e) {
                log.error("本次队列消费失败!!!! 具体错误如下" + e);
                log.error("失败将使用延迟队列, 队列id==>>>{}, 消息主题==>>{}",
                        queueContentModel.getId(),
                        queueContentModel.getSubject());
                // 记录本次消息失败的具体错误信息
                paymentCallbackModel.setStatus(-1);
                paymentCallbackModel.setExceptionName(e.getClass().getName());
                paymentCallbackModel.setExceptionInfo(e.getMessage());

                if (thisQueueContent.getIsManual() == 0) {
                    Integer count = queueContentModel.getCount() + 1;
                    thisQueueContent.setCount(count);
                    thisQueueContent.setDelayTime(count * BASIC_DELAY_TIME);
                    thisQueueContent.setData(paymentCallbackModel);
                    log.error("正在执行消息重发操作");

                    mqSender.sendMQMessage(
                           RabbitmqConstant.EXCHANGE_DELAYED,
                           RabbitmqConstant. DELAY_PAYMENT_CALLBACK,
                           thisQueueContent
                    );
                }
            } finally {
                paymentCallbackModel.setCallBackTime(currentTime);
                finalResultDataRecord(queueContentModel, paymentAttachModel, currentTime);

            }
        }
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
    }

    /**
     *  执行退款, 队列相关数据
     * @param message
     * @param queueContentModel
     * @param channel
     * @throws IOException
     */
    @RabbitListener(queues = RabbitmqConstant.QUEUE_PAYMENT_REFUND)
    public void refundQueueHandler(Message message, QueueContentModel queueContentModel, Channel channel) throws IOException {
        log.info("退款 正在进行支付模块数据消费!!!! 队列id==>>>{}, 消息主题为==>>>{}, 已消费了==>>>{}次",
                queueContentModel.getId(),
                queueContentModel.getSubject(),
                queueContentModel.getCount());
        Long currentTime = TimeUtil.getCurrentTime();
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
    }

    /**
     * 处理延迟队列相关
     * @param message
     * @param queueContentModel
     * @param channel
     * @throws IOException
     */
    //@RabbitListener(queues = "handler")
    public void delayQueueHandler(Message message, QueueContentModel queueContentModel, Channel channel) throws IOException {
        log.info("延迟队列!!!! 队列id==>>>{}, 消息主题为==>>>{}, 已消费了==>>>{}次",
                queueContentModel.getId(),
                queueContentModel.getSubject(),
                queueContentModel.getCount());
        Long currentTime = TimeUtil.getCurrentTime();
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
    }




    /**
     * 执行用户所给的webhook地址
     * @param webhook
     * @param body
     * @return
     * @throws BusinessException
     */
    protected String executeUserWebhook(String webhook, String body) throws BusinessException {
        if (StringUtil.isEmpty(webhook)) {
            log.error("用户设置的异步回调地址为空, 或 不符合规则" + webhook);
            throw new BusinessException();
        }
        HttpResponse response = HttpRequest.post(webhook)
                .body(body)
                .execute();
        return response.body();
    }

    /**
     * 队列最终处理数据记录
     * @param queueModel
     * @param mqSubsetModel
     * @param currentTime
     */
    protected void finalResultDataRecord(QueueContentModel queueModel,
                                         PaymentAttachModel mqSubsetModel,
                                         Long currentTime) {
        queueModel.setLastDate(currentTime);

    }
}
